package org.andao.core.dao.hibernate;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.andao.core.annotation.DeleteChild;
import org.andao.core.base.model.Model;
import org.andao.core.base.model.RootModel;
import org.andao.core.dao.helper.GenericsUtils;
import org.andao.core.dao.helper.HibernateHelper;
import org.andao.core.dao.helper.OrderBy;
import org.andao.core.dao.helper.Page;
import org.andao.core.dao.helper.PaginationParameter;
import org.andao.core.exception.ServiceException;
import org.andao.core.utils.ExBeanUtils;
import org.andao.core.utils.ExCollectionUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.impl.CriteriaImpl.OrderEntry;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;


/**
 * 基础的hibernate Dao模板.
 *  
 * @author Seewo software - Marco.hu(huzhiguo@cvte.cn)
 */
public class BaseHibernateTemplate extends HibernateDaoSupport {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	public BaseHibernateTemplate(){}
	
	/**构造方法，赋值sessionFactory*/
	public BaseHibernateTemplate(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}
	
	

	/**
	 * 根据实体ID获取实体对象.
	 * @param clazz 需要获取的对象类型
	 * @param id 序列化后的ID
	 * @return	实体对象.
	 */
	public Object get(Class<?> clazz, Serializable id){		
		return getHibernateTemplate().get(clazz, id);
	}

	/**
	 * load对象
	 * @param clazz 对象类型
	 * @param id ID
	 * @return 实体对象	
	 */
	public Object load(Class<?> clazz, final Serializable id){
		return getHibernateTemplate().load(clazz, id);
	}

	/**
	 * 根据hql语句查找唯一对象.
	 * @param hql hql语句
	 * @param values 参数可变，按顺序绑定
	 * @return 对象
	 */
	@SuppressWarnings("unchecked")
	public <X> X findUnique(String hql, Object... values) {
		Assert.hasText(hql, "hql不能为空");
		return (X) createQuery(hql, values).uniqueResult();
	}

	/**
	 * 根据hql语句查找唯一对象.
	 * @param <X>
	 * @param hql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <X> X findUnique(final String hql, final Map<String, Object> values) {
		return (X) createQuery(hql, values).uniqueResult();
	}

	/**
	 * 根据属性查找唯一对象.
	 * @param clazz 对象类型
	 * @param propertyName 属性名
	 * @param value 属性值
	 * @return 对象	
	 */
	public Object findUniqueByProperty(Class<?> clazz, String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName不能为空");
		return createCriteria(clazz,Collections.<String, Integer> emptyMap(), Restrictions.eq(propertyName, value)).uniqueResult();
	}

	/**
	 * 获取实体全部列表(loadAll方式).
	 * @param clazz 实体类型
	 * @return 返回实体列表.	
	 */
	public List<?> getAll(Class<?> clazz) {
		return getHibernateTemplate().loadAll(clazz);
	}

	/**
	 * 获取实体全部列表(criteria方式)，推荐使用这种方式.
	 * @param clazz 实体类型
	 * @see #findByCriteria(Class, Criterion[])
	 * @return 返回实体列表.	
	 */
	public List<?> getAllBycriteria(Class<?> clazz) {
		return findByCriteria(clazz);
	}

	/**
	 * 获取实体全部分页列表.
	 * 使用criteria方式查找.
	 * @param clazz 实体类型	
	 * @param page
	 * @see #findByCriteria(Class clazz,Page page, Criterion... criterion)
	 * @return 分页查询结果
	 */
	public Page getAllBycriteria(Class<?> clazz, Page page) {
		return findByCriteria(clazz, page);
	}

	/**
	 * 保存或更新.
	 * @param entity	
	 */
	public void saveOrUpdate(Object entity) {
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().saveOrUpdate(entity);
		logger.debug("saveOrUpdate entity: {}", entity);
	}	
		
	/**
	 * 批量保存或更新.
	 * @param entity
	 */	
	public void saveOrUpdateCollection(Collection<? extends RootModel> entities) {
		Assert.notNull(entities, "entities不能为空");
		getHibernateTemplate().saveOrUpdateAll(entities);
		logger.debug("saveOrUpdate entitys: {}", entities);
	}

	/**
	 * 保存
	 * @param entity
	 * @return  实体对象.	
	 */
	public Object save(Object entity) {
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().save(entity);
		logger.debug("save entity: {}", entity);
		return entity;
	}

	/**
	 * 更新
	 * @param entity	
	 */
	public void update(Object entity){
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().update(entity);
		logger.debug("update entity: {}", entity);
	}

	/**
	 * merge方式更新
	 * @param entity
	 * @return 实体	
	 */
	public Object merge(Object entity){
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().merge(entity);
		logger.debug("merge entity: {}", entity);
		return entity;
	}

	/**
	 * persist方式保存
	 * @param entity
	 */
	public void persist(Object entity) {
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().persist(entity);
		logger.debug("persist entity: {}", entity);
	}

	/**
	 * 物理删除实体
	 * @param entity
	 */
	public void truncate(Object entity){
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().delete(entity);
		logger.debug("delete entity:{}",entity);
	}
	
	/**
	 * 根据属性删除（物理）
	 * @param clazz
	 * @param propertyName
	 * @param value	
	 */
	public void truncateByProperty(Class clazz, String propertyName, String value) {
		StringBuffer hql = new StringBuffer();
		hql.append("delete ").append(clazz.getName()).append(" where ").append(propertyName).append(" = ").append("'").append(value).append("'");
		this.createQuery(hql.toString()).executeUpdate();
	}
	
	/**
	 * 物理批量删除
	 * @param clazz
	 * @param ids
	 */
	public void batchTruncate(Class<?> clazz,final String[] ids) {
		Assert.notNull(ids);
		final String queryStr = "delete "+clazz.getSimpleName()+" where resourceid in (:ids)";
		getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(queryStr);
                query.setParameterList("ids", ids);
                return query.executeUpdate();
            }
        });
	}
	
	/**
	 * 删除（软删除）对象.
	 * @param entity	 
	 */
	public void delete(Object entity) {
		Assert.notNull(entity, "entity不能为空");		
		try {
			final String resourceid =  (String)ExBeanUtils.getFieldValue(entity, "resourceid");
			final String queryStr = "update " + entity.getClass().getSimpleName() + " set isDeleted = 1 where resourceid = :id";
								
			getHibernateTemplate().execute(new HibernateCallback() {
				public Object doInHibernate(Session session) throws HibernateException, SQLException {
					Query query = session.createQuery(queryStr);	
					query.setString("id",resourceid );
					//TODO 如果声明了关联检查，则执行检查回调
					
					return query.executeUpdate();
				}
			});
			//针对一对多的实体，如果有子表，则删除子表，
			//多对多的情况不做处理						
			List<Collection<Model>> childEntryList = getChildEntityName(entity);
			if(null != childEntryList && childEntryList.size()>0){
				for(Collection<Model> collection : childEntryList){//遍历多个子
					if(null != collection && collection.size()>0){//遍历子
						for(Model childEntry : collection){
							delete(childEntry.getClass(), childEntry.getResourceid());
						}
					}					
				}
			}
					
		} catch (Exception e) {		
			 logger.error("删除实体出错:"+e.fillInStackTrace());
			 throw new ServiceException("删除实体"+entity.getClass().getSimpleName()+"出错!");
		}	
		
		logger.debug("delete entity: {}", entity);
	}
	
	protected boolean doCheckEntityRelation(Object entity){
		return false;
	}
	
	/**
	 * 获取实体子类型
	 * @param collection
	 * @return map<String,Object> key -子实体类型,子数据
	 */
	@SuppressWarnings("unchecked")
	protected List<Collection<Model>> getChildEntityName(Object entity){
		List<Collection<Model>> childEntiryList = new ArrayList<Collection<Model>>();
		PropertyDescriptor[] oldPds = PropertyUtils .getPropertyDescriptors(entity); 
		try {
			 for (int i = 0; i < oldPds.length; i++) {  
				 PropertyDescriptor oldPd = oldPds[i]; 	
				 if(null == oldPd.getWriteMethod()) continue;
				if(!oldPd.getDisplayName().equals("class")){//排除掉class类型的
					Object indate = PropertyUtils.getNestedProperty(entity,oldPd.getDisplayName());
					Field field = ExBeanUtils.getDeclaredField(entity.getClass(), oldPd.getDisplayName());
					if(null != indate && indate instanceof Collection<?>){
						//如果注解为不删除子表的忽略
						DeleteChild deleteChild = field.getAnnotation(DeleteChild.class);//获取不删除的注解
						if(null != deleteChild && !deleteChild.deleteable()){
							continue;
						}
						childEntiryList.add((Collection<Model>)indate);
						//childEntiryMap.put(GenericsUtils.getFieldGenericType(field).getName(), indate);						
						logger.debug("==>获取实体"+entity.getClass().getSimpleName()+"子类型："+GenericsUtils.getFieldGenericType(field).getName());
					}		
				
				}
			
			 }	
		} catch (Exception e) {
			throw new ServiceException("删除实体："+entity.getClass().getName()+" 子对象出错："+e.getMessage());
		}
		 
		return childEntiryList;
	}

	/**
	 * 批量删除对象(软删除)
	 * @param clazz	实例类型
	 * @param ids	对象ID集合	
	 */
	public void batchDelete(Class<?> clazz, final String[] ids) {
		Assert.notNull(ids, "ids不能为空");
		for (int i = 0; i < ids.length; i++) {
			delete(clazz, ids[i]);
		}
		logger.debug("delete from entites:{}", ids);
	}
	
	/**
	 * 批量删除对象(软删除)
	 * @param list	 
	 */
	public void batchDelete(final List<?> list) {
		Assert.notNull(list, "list不能为空");
		for (int i = 0; i < list.size(); i++) {
			delete(list.get(i));
		}
	}
	

	/**
	 * 批量保存或更新	
	 * @param list 需要更新或保存的实体列表.	
	 */
	public void batchSaveOrUpdate(final List<? > list) {
		Assert.notNull(list, "list不能为空");
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				int rows = 0;
				for (int i = 0; i < list.size(); i++) {
					session.saveOrUpdate(list.get(i));
					rows++;
					if (rows % 10000 == 0) {
						//将本批插入的对象立即写入数据库并释放内存
						session.flush();
						session.clear();
					}
				}
				logger.debug("save or update entites row:" + rows);
				return rows;
			}
		});
	}
	
	/**
	 * 执行传入的删除、修改HQL语句
	 * @param hql  HQL语句 
	 * @param map  hql语句中的参数
	 * @return	
	 */
	public int executeHQL(final String hql, final Map<String,Object> param)  {		
		
		int rows = 0;		
		Assert.notNull(hql,"hql不能为空");		
		Object object = getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                query.setProperties(param);
                return query.executeUpdate();
            }
        });
		rows = (Integer)object;
		return rows;
	}
	
	/**
	 * 根据对象ID删除
	 * @param clazz 实体类型
	 * @param id 实体ID	
	 */
	public void delete(Class<?> clazz, Serializable id) {
		Assert.notNull(id, "id不能为空");		
		delete(get(clazz, id));
		logger.debug("delete entity by id: {}", id);
	}

	/**
	 * flush 	 
	 */
	public void flush() {
		getHibernateTemplate().flush();
	}

	/**
	 * 清空指定对象缓存
	 * @param entity	
	 */
	public void clearCache(Object entity) {
		Assert.notNull(entity, "entity不能为空");
		getHibernateTemplate().evict(entity);
//		logger.debug("clear entity from cache:{}" + entity);
	}

	/**
	 * 清空所有缓存	
	 */
	public void clearAllCache() {
		getHibernateTemplate().clear();
		logger.debug("clear all cache...");
	}

	/**
	 * 重新初始化proxy实体.
	 * @param proxy	
	 */
	public void reloadLazy(Object proxy) {
		Assert.notNull(proxy, "proxy不能为空");
		getHibernateTemplate().initialize(proxy);
		logger.debug("initialize proxy: {}", proxy);
	}

	/**
	 * 使用HQL方式查找对象列表.
	 * @param hql HQL语句  
	 * @param values hql语句中的query参数对象
	 * @return 实体列表.	
	 */
	public List<?> findByHqlQuery(String hql, Object bean) {
		Assert.hasText(hql);
		Query queryObject = getSession().createQuery(hql);
		if (null != bean) {
			queryObject.setProperties(bean);
		}
		return queryObject.list();
	}
	/**
	 * 使用HQL方式查找对象列表.
	 * @param hql HQL语句  
	 * @param values hql语句中的query参数对象
	 * @return 实体列表.	
	 */
	public Page findByHqlQuery(Page objPage,String hql, Object bean) {
		Assert.notNull(objPage, "objPage不能为空");
		Assert.hasText(hql);
		Query q = getSession().createQuery(hql);
		if (null != bean) {
			q.setProperties(bean);
		}
		if (objPage.isAutoCount()) {
			String fromHql = hql;
			//select子句与order by子句会影响count查询,进行简单的排除.
			fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
			fromHql = StringUtils.substringBefore(fromHql, "order by");
			if(fromHql.indexOf("group by")>-1) fromHql = StringUtils.substringBefore(fromHql, "group by");
			String countHql = "select count(*) " + fromHql ;
			Long totalCount = (Long) getSession().createQuery(countHql).setProperties(bean).uniqueResult();
			objPage.setTotalCount(Long.valueOf(totalCount).intValue());
		}
		//设置分页参数
		setPageParameter(q, objPage);
		List result = q.list();
		objPage.setResult(result);
		return objPage;
	}
	
	/**
	 * 使用HQL方式查找对象列表.
	 * @param hql HQL语句  
	 * @param values hql语句中的参数
	 * @return 实体列表.	
	 */
	public List<?> findByHql(String hql, Object... values) {
		return createQuery(hql, values).list();
	}
	
	/**
	 * 使用HQL方式查找对象列表.
	 * @param hql  HQL语句 
	 * @param map  hql语句中的参数
	 * @return	 
	 */	
	public List<?> findByHql(final String hql,final Map<String,Object> map) {	
		
		if(!map.isEmpty()){
			return getHibernateTemplate().executeFind(new HibernateCallback() {				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,	SQLException {
					Query queryObject = session.createQuery(hql);
					Set<Entry<String,Object>> set = map.entrySet();
					for(Entry<String,Object> ent : set){
						if(ent.getValue() instanceof Collection){//对于in(:ids)
							queryObject.setParameterList(ent.getKey().toString(), (Collection<?>)ent.getValue());	
						}else if(ent.getValue() instanceof Object[]){
							queryObject.setParameterList(ent.getKey().toString(), (Object[])ent.getValue());
						}else {
							queryObject.setParameter(ent.getKey().toString(), ent.getValue());
						}
					}
					return queryObject.list();
					
				}
			});
		}
		
		return Collections.EMPTY_LIST;
	}

	/**
	 * 按HQL分页查询.
	 * 
	 * @param page 分页参数.
	 * @param hql hql语句.
	 * @param values 命名参数,按名称绑定.
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询时的参数.
	 */
	public Page findByHql(Page page, String hql, Map<String, Object> values) {
		Assert.notNull(page, "page不能为空");

		Query q = createQuery(hql, values);

		if (page.isAutoCount()) {
			long totalCount = countHqlResult(hql, values);
			page.setTotalCount(Long.valueOf(totalCount).intValue());
		}
		//设置分页参数
		setPageParameter(q, page);
		List result = q.list();
		page.setResult(result);
		return page;
	}
	
	/**
	 * 按Sql分页查询.
	 * 
	 * @param page 分页参数.
	 * @param sql sql语句.
	 * @param props 命名参数,按名称绑定.(支持object,map)
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询时的参数.
	 */
	public Page findBySql(Page page, String sql,Class<?> targetClazz, Object props) {
		Assert.notNull(page, "page不能为空");
		
		Query q = getSession().createSQLQuery(sql).setProperties(props).setResultTransformer(Transformers.aliasToBean(targetClazz));
		
		if (page.isAutoCount()) {
			page.setTotalCount(Long.valueOf(countSqlResult(sql, props)).intValue());
		}
		//设置分页参数
		setPageParameter(q, page);
		List result = q.list();
		page.setResult(result);
		return page;
	}

	/**
	 * 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数. 
	 * @param clazz 实体类型
	 * @param criterion Criterion条件.
	 * @return 实体列表 	
	 */
	public List<?> findByCriteria(Class<?> clazz, Criterion... criterion){
		return createCriteria(clazz,Collections.<String, Integer> emptyMap(), criterion).list();
	}

	/**
	 * 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数. 
	 * @notice 增加一个可选参数Order[]
	 * @param clazz 实体类型
	 * @param criterion Criteriont条件数组.
	 * @param order2 排序条件，可以为多个，自动绑定
	 * @return 实体列表
	 */
	public List<?> findByCriteria(Class<?> clazz, Criterion[] criterion, Integer firstResult, Integer maxResults,
			Order... order2) {
		Criteria criteria = createCriteria(clazz,Collections.<String, Integer> emptyMap(), criterion);
		for (Order order : order2) {
			criteria.addOrder(order);
		}
		if (firstResult != null)
			criteria.setMaxResults(firstResult);
		if (maxResults != null)
			criteria.setMaxResults(maxResults);
		return criteria.list();
	}

	/***
	 * 按Criteria查询列表	，这个Criteria为自己封装好的Criterion条件.
	 * @author: Snoopy Chen (ctfzh@yahoo.com.cn)
	 * @since： Jun 9, 2009 
	 * @param c 查询条件
	 * @return 实体列表	
	 */
	public List<?> findByCriteriaSession(Criteria c) {
		return c.list();
	}

	/**
	 * 按Criterion分页查询.
	 * @param clazz 实体类型
	 * @param page 分页参数.包括pageSize、firstResult、orderBy、asc、autoCount.
	 *             其中firstResult可直接指定,也可以指定pageNo.
	 *             autoCount指定是否动态获取总结果数.
	 *             
	 * @param criterion 数量可变的Criterion.
	 * @param see {@link #countQueryResult(Page, Criteria)}
	 * @return 分页查询结果.附带结果列表及所有查询时的参数.
	 */
	public Page findByCriteria(Class<?> clazz, Page page, Criterion... criterion){	
		return findByCriteria(clazz,page,Collections.<String, Integer> emptyMap(),criterion);
	}
	
	/**
	 * 按Criterion分页查询.
	 * @param clazz
	 * @param page
	 * @param fetchMode 针对特定field的查询模式.
	 * @param criterion
	 * @return
	 */
	public Page findByCriteria(Class<?> clazz, Page page,Map<String, Integer> fetchMode,Criterion... criterion){
		Assert.notNull(page, "page不能为空");
		Criteria c = createCriteria(clazz,fetchMode, criterion);
		this.findByCriteriaCommon(page, c);
		return page;
	}

	/**
	 * 按Criteria 别名分页查询，用于多表关联查询
	 * @param clazz 实体类型
	 * @param page 分页对象
	 * @param alias 实体别名
	 * @param criterion 查询条件
	 * @return 实体分页列表
	 */
	public Page findByCriteriaWithAlias(Class<?> clazz, Page page, String[] alias, Criterion... criterion)	{
		Assert.notNull(page, "page不能为空");

		Criteria c = getSession().createCriteria(clazz);
		if (alias != null) {
			for (int i = 0; i < alias.length; i++) {
				String[] as = alias[i].split(":");
				if (as != null && as.length == 2) {
					c.createAlias(as[1], as[0]);
					logger.debug("creating alias:{},{}", as[1], as[0]);
				}
			}
		}
		for (Criterion cx : criterion) {
			c.add(cx);
		}

		if (page.isAutoCount()) {//如果允许自动统计,统计totalCount
			page.setTotalCount(countQueryResult(page, c));
		}
		if (page.isFirstSetted()) {
			c.setFirstResult(page.getFirst());
		}
		if (page.isPageSizeSetted()) {
			c.setMaxResults(page.getPageSize());
		}
		/*
		 * modify by hzg
		if (page.isOrderBySetted()) {
			if (page.getOrder().equalsIgnoreCase(PaginationParameter.ASC)) {
				c.addOrder(Order.asc(page.getOrderBy()));
			} else {
				c.addOrder(Order.desc(page.getOrderBy()));
			}
		}
		*/
		if(ExCollectionUtils.isNotEmpty(page.getOrderList())){
			for(OrderBy order : page.getOrderList()){
				if(order.getOrder().equalsIgnoreCase(PaginationParameter.ASC)){
					c.addOrder(Order.asc(order.getOrderBy()));
				}else{
					c.addOrder(Order.desc(order.getOrderBy()));
				}
			}
		}
		if (page.getTotalCount() > 0) {
			page.setResult(c.list());
		}
		return page;
	}

	/**
	 * 根据ID集合查找实体列表
	 * @param clazz 实体类型
	 * @param values ID集合
	 * @return
	 */
	public List<?> findEntitysByIds(Class<?> clazz, Collection<String> values)  {
		Assert.notNull(values);	
		String hql = "from " + clazz.getSimpleName() + " as entity where entity.resourceid in(:ids) and entity.isDeleted = :isdeleted";
		Query queryObject = getSession().createQuery(hql);
		queryObject.setParameterList("ids", values);
		queryObject.setParameter("isdeleted", 0);
		return queryObject.list();
	}

	/**
	 * 按Criterion分页查询,级联查询与非级联查询的公用部分.
	 * @param clazz 实体类型
	 * @param page 分页参数.包括pageSize、firstResult、orderBy、asc、autoCount.
	 *             其中firstResult可直接指定,也可以指定pageNo.
	 *             autoCount指定是否动态获取总结果数.
	 *             
	 * @param criterion 数量可变的Criterion.
	 * @param see {@link #countQueryResult(Page, Criteria)}
	 * @return 分页查询结果.附带结果列表及所有查询时的参数.
	 */
	private void findByCriteriaCommon(Page page, Criteria c) {
		if (page.isAutoCount()) {//如果允许自动统计,统计totalCount
			page.setTotalCount(countQueryResult(page, c));
		}
		if (page.isFirstSetted()) {
			c.setFirstResult(page.getFirst());
		}
		if (page.isPageSizeSetted()) {
			c.setMaxResults(page.getPageSize());
		}
		/*
		 * modify by hzg,使用排序列表.
		if (page.isOrderBySetted()) {
			if (page.getOrder().equalsIgnoreCase(PaginationParameter.ASC)) {
				c.addOrder(Order.asc(page.getOrderBy()));
			} else {
				c.addOrder(Order.desc(page.getOrderBy()));
			}
		}
		*/
		
		if(ExCollectionUtils.isNotEmpty(page.getOrderList())){
			for(OrderBy order : page.getOrderList()){
				if(order.getOrder().equalsIgnoreCase(PaginationParameter.ASC)){
					c.addOrder(Order.asc(order.getOrderBy()));
				}else{
					c.addOrder(Order.desc(order.getOrderBy()));
				}
			}
		}

		if (page.getTotalCount() > 0) {
			page.setResult(c.list());
		}
	}

	/**
	 * 执行count查询获得本次Hql查询所能获得的对象总数.
	 * 
	 * 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
	 */
	protected long countHqlResult(final String hql, final Map<String, Object> values) {
		String fromHql = hql;
			
		//select子句与order by子句会影响count查询,进行简单的排除.
		fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
		fromHql = StringUtils.substringBefore(fromHql, "order by");
		if(fromHql.indexOf("group by")>-1) fromHql = StringUtils.substringBefore(fromHql, "group by");

		String countHql = "select count(*) " + fromHql ;

		try {
			Long count = findUnique(countHql, values);
			return count;
		} catch (Exception e) {
			throw new RuntimeException("hql can't be auto count, hql is:" + countHql, e);
		}
	}
	
	/**
	 * 执行count查询获得本次Sql查询所能获得的对象总数.
	 * 
	 * 本函数只能自动处理简单的Sql语句,复杂的Sql查询请另行编写count语句查询.
	 */
	protected long countSqlResult(final String sql, final Object props) {
		String fromSql = sql;
		
		//select子句与order by子句会影响count查询,进行简单的排除.
		fromSql = "from " + StringUtils.substringAfter(fromSql, "from");
		fromSql = StringUtils.substringBefore(fromSql, "order by");
		if(fromSql.indexOf("group by")>-1) fromSql = StringUtils.substringBefore(fromSql, "group by");
		
		String countSql = "select count(*) " + fromSql ;
		
		try {
			Assert.hasText(sql, "sql不能为空");
			Long count = ((Number) getSession().createSQLQuery(countSql).setProperties(props).uniqueResult()).longValue();
			return count;
		} catch (Exception e) {
			throw new RuntimeException("sql can't be auto count, sql is:" + countSql, e);
		}
	}

	/**
	 * 设置分页参数到Query对象,辅助函数.
	 */
	protected Query setPageParameter(final Query q, final Page page) {
		//hibernate的firstResult的序号从0开始		
		q.setFirstResult(page.getFirst());
		q.setMaxResults(page.getPageSize());	
		return q;
	}

	/**
	 *  根据查询函数与参数列表创建Query对象,后续可进行更多处理,辅助函数.
	 * @param queryString
	 * @param values
	 * @return
	 */
	protected Query createQuery(String queryString, Object... values) {
		Assert.hasText(queryString);
		Query queryObject = getSession().createQuery(queryString);
		if (null != values) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(i, values[i]);
			}
		}
		return queryObject;
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * 
	 * @param values 命名参数,按名称绑定.
	 */
	protected Query createQuery(final String queryString, final Map<String, Object> values) {
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
//		if (values != null) {			
//			query.setProperties(values);
//		}	
		if (values != null) {
			Set<String> keySet = values.keySet();
			for (String string : keySet) {
				Object obj = values.get(string);
				// 这里考虑传入的参数是什么类型，不同类型使用的方法不同
				if (obj instanceof Collection<?>) {
					//兼容 name in :props
					query.setParameterList(string, (Collection<?>) obj);
				} else if (obj instanceof Object[]) {
					query.setParameterList(string, (Object[]) obj);
				} else {
					query.setParameter(string, obj);
				}
			}
		}
		return query;
	}

	/**
	 * 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数.
	 * HQL运算符 QBC运算符 含义
		= Restrictions.eq() 等于
		<> Restrictions.not(Exprission.eq()) 不等于
		> Restrictions.gt() 大于
		>= Restrictions.ge() 大于等于
		< Restrictions.lt() 小于
		<= Restrictions.le() 小于等于
		is null Restrictions.isnull() 等于空值
		is not null Restrictions.isNotNull() 非空值
		like Restrictions.like() 字符串模式匹配
		and Restrictions.and() 逻辑与
		and Restrictions.conjunction() 逻辑与
		or Restrictions.or() 逻辑或
		or Restrictions.disjunction() 逻辑或
		not Restrictions.not() 逻辑非
		in(列表) Restrictions.in() 等于列表中的某一个值
		ont in(列表) Restrictions.not(Restrictions.in())不等于列表中任意一个值
		between x and y Restrictions.between() 闭区间xy中的任意值
		not between x and y Restrictions.not(Restrictions..between()) 小于值X或者大于值y
	 * @param clazz 对象类型
	 * @param criteria
	 */
	protected Criteria createCriteria(Class<?> clazz,Map<String,Integer> fetchMode, Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(clazz);
		if(fetchMode != null && !fetchMode.isEmpty()){
			for(String fieldName : fetchMode.keySet()){	
				switch (fetchMode.get(fieldName)) {
				case HibernateHelper.SELECT:
					criteria.setFetchMode(fieldName, org.hibernate.FetchMode.SELECT);
					break;
				case HibernateHelper.JOIN:
					criteria.setFetchMode(fieldName, org.hibernate.FetchMode.JOIN);
					break;
				case HibernateHelper.LAZY:
					criteria.setFetchMode(fieldName, org.hibernate.FetchMode.LAZY);
					break;
				case HibernateHelper.EAGER:
					criteria.setFetchMode(fieldName, org.hibernate.FetchMode.EAGER);
					break;
				}
			}
		}
		if (null != criterions && criterions.length > 0) {
			for (Criterion c : criterions) {
				criteria.add(c);
			}
		}
		return criteria;
	}

	/**
	 * 通过count查询获得本次查询所能获得的对象总数.
	 * @return page对象中的totalCount属性将赋值.
	 */
	@SuppressWarnings("unchecked")
	protected int countQueryResult(Page page, Criteria c) {
		CriteriaImpl impl = (CriteriaImpl) c;

		// 先把Projection、ResultTransformer、OrderBy取出来,清空三者后再执行Count操作
		Projection projection = impl.getProjection();
		ResultTransformer transformer = impl.getResultTransformer();

		List<CriteriaImpl.OrderEntry> orderEntries = null;
		try {
			orderEntries = (List<OrderEntry>) ExBeanUtils.getFieldValue(impl, "orderEntries");
			ExBeanUtils.setFieldValue(impl, "orderEntries", new ArrayList());
		} catch (Exception e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}

		// 执行Count查询
		int totalCount = (Integer) c.setProjection(Projections.rowCount()).uniqueResult();
		if (totalCount < 1)
			return -1;

		// 将之前的Projection和OrderBy条件重新设回去
		c.setProjection(projection);

		if (projection == null) {
			c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		}
		if (transformer != null) {
			c.setResultTransformer(transformer);
		}

		try {
			ExBeanUtils.setFieldValue(impl, "orderEntries", orderEntries);
		} catch (Exception e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}

		return totalCount;
	}
}
